#ifndef SLAVE_GROUP_H
#define SLAVE_GROUP_H

#include <isl/schedule_node.h>
#include <isl/constraint.h>
#include "slave.h"

struct slave_group_reply_info {
	isl_ast_expr *reply_lower;
	isl_ast_expr *reply_upper;
	isl_ast_expr *reply_inc;
};

struct slave_group_rma_reply_info {
	struct slave_array_ref_group *group;
	char *reply_l;
	char *reply_r;
};

struct slave_group_rma_info {
	int from_group;
	int row;
	int col;
	isl_ast_expr *iterator;
	struct slave_group_rma_reply_info *rma_reply;
};

/* A group of array references in a kernel that should be handled together.
 * If private_tile is not NULL, then it is mapped to registers.
 * Otherwise, if shared_tile is not NULL, it is mapped to shared memory.
 * Otherwise, it is accessed from global memory.
 * Note that if both private_tile and shared_tile are set, then shared_tile
 * is only used inside group_common_shared_memory_tile.
 */
struct slave_array_ref_group {
	/* The references in this group access this local array. */
	struct slave_local_array_info *local_array;
	/* This is the corresponding array. */
	struct slave_array_info *array;
	/* Position of this group in the list of reference groups of array. */
	int nr;

	/* The following fields are use during the construction of the groups.
	 * access is the combined access relation relative to the private
	 * memory tiling.  In particular, the domain of the map corresponds
	 * to the first thread_depth dimensions of the kernel schedule.
	 * write is set if any access in the group is a write.
	 * exact_write is set if all writes are definite writes.
	 * slice is set if there is at least one access in the group
	 * that refers to more than one element
	 * "min_depth" is the minimum of the tile depths and thread_depth.
	 */
	isl_map *access;
	int write;
	int exact_write;
	int slice;
	int min_depth;

	/* The shared memory tile, NULL if none. */
	struct slave_array_tile *ldm_tile;

	/* The private memory tile, NULL if none. */
	//struct slave_array_tile *private_tile;

	/* References in this group; point to elements of a linked list. */
	int n_ref;
	struct slave_stmt_access **refs;

	int flag_get_reply;	
	int flag_put_reply;
	struct ppcg_kernel_reply *get_reply;
	struct ppcg_kernel_reply *put_reply;

	struct slave_group_rma_info *rma_info;

	int buffer;
	int buf_group;
//	int n_reply_dim;
//	struct slave_group_reply_info **group_reply;
};

int slave_group_references(struct ppcg_kernel *kernel,
	__isl_keep isl_schedule_node *node);

__isl_give isl_printer *slave_array_reply_print_name(
	struct slave_array_ref_group *group, __isl_take isl_printer *p, int read);
__isl_give isl_printer *slave_array_ref_group_print_name(
	struct slave_array_ref_group *group, __isl_take isl_printer *p);
void slave_array_ref_group_compute_tiling(struct slave_array_ref_group *group);
__isl_give isl_union_map *slave_array_ref_group_access_relation(
	struct slave_array_ref_group *group, int read, int write);
int slave_array_ref_group_requires_unroll(struct slave_array_ref_group *group);
enum ppcg_group_access_type slave_array_ref_group_type(
	struct slave_array_ref_group *group);
struct slave_array_tile *slave_array_ref_group_tile(
	struct slave_array_ref_group *group);
struct slave_array_ref_group *slave_array_ref_group_free(
	struct slave_array_ref_group *group);

#endif
